<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!--

Generated from t-y-scheme.tex by tex2page, v 20070609
(running on MzScheme 4.2.1, unix), 
(c) Dorai Sitaram, 
http://www.ccs.neu.edu/~dorai/tex2page/tex2page-doc.html

-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
Teach Yourself Scheme in Fixnum Days 中文版
</title>
<link rel="stylesheet" type="text/css" href="t-y-scheme-Z-S.css" title=default>
<meta name="robots" content="index,follow">
<meta name=description content="A practical
introduction to the programming language Scheme">

<meta name=author content="Dorai Sitaram">

<link rev=made href="mailto:dorai @ ccs.neu.edu">
</head>
<body>
<div id=slidecontent>
<div align=right class=navigation>[Go to <span><a href="t-y-scheme.html">first</a>, <a href="t-y-scheme-Z-H-4.html">previous</a></span><span>, <a href="t-y-scheme-Z-H-6.html">next</a></span> page<span>; &nbsp;&nbsp;</span><span><a href="t-y-scheme-Z-H-1.html#node_toc_start">contents</a></span><span><span>; &nbsp;&nbsp;</span><a href="t-y-scheme-Z-H-25.html#node_index_start">index</a></span>]</div>
<p></p>
<a name="node_chap_3"></a>
<h1 class=chapter>
<div class=chapterheading><a href="t-y-scheme-Z-H-1.html#node_toc_node_chap_3"> 第 3 章 </a></div>
<br>
<a href="t-y-scheme-Z-H-1.html#node_toc_node_chap_3">Forms</a></h1>
<p> 读者可能已经注意到到目前为止提供的 Scheme 程序例子也是 S 表达式 。对于所有的 Scheme 程序来讲，程序就是数据。 </p>
<p>因此，字符 <code class=scheme><span class=selfeval>#\c</span></code> 是一个程序，或是一个<em>形式</em>（<em>form</em>）。我们将使用更一般的术语<em>形式</em>来代替<em>程序</em>，使得我们也可以处理程序片段。</p>
<p> Scheme 对形式 <code class=scheme><span class=selfeval>#\c</span></code> 求值得到 <code class=scheme><span class=selfeval>#\c</span></code>，  因为  <code class=scheme><span class=selfeval>#\c</span></code> 是自求值的。不是所有的 S 表达式都是自求值的。举个例子，符号 S 表达式 <code class=scheme><span class=variable>xyz</span></code> 求值将得到<em>变量</em><code class=scheme><span class=variable>xyz</span></code> 保存的值。表 S 表达式 <code class=scheme>(<span class=variable>string-&gt;number</span> <span class=selfeval>&quot;16&quot;</span>) </code>求值得到 16。</p>

<p>不是所有的 S 表达式都是合法的程序。如果你在 Scheme 监听器中键入点对 S 表达式 <code class=scheme>(<span class=selfeval>1</span> . <span class=selfeval>2</span>)</code> ，你将会得到一个错误。</p>
<p> Scheme在对一个表形式求值时，会检查它的第一个元素，或叫 <em>head</em> 元素。 如果第一个元素求值得到的是一个过程，剩下的将被求值得到该过程的参数，然后这个过程被<em>应用</em>（<em>applied</em>）到这些参数上。 </p>
<p> 如果形式的第一个元素是一个<em>特殊形式</em>，求值会以一种特别的方式进行。一些我们已经看到的特殊的形式有 <code class=scheme><span class=keyword>begin</span></code>，<code class=scheme><span class=keyword>define</span></code>，和 <code class=scheme><span class=keyword>set!</span></code>。<code class=scheme><span class=keyword>begin</span></code> 使它的子式有序地求值，整个形式的结果就是最后那个子式求值的结果。 <code class=scheme><span class=keyword>define</span></code> 引入并初始化一个变量。<code class=scheme><span class=keyword>set!</span></code> 改变变量的约束。</p>
<p>
<a name="node_idx_238"></a><a name="node_idx_240"></a></p>
<a name="node_sec_3.1"></a>
<h2 class=section><a href="t-y-scheme-Z-H-1.html#node_toc_node_sec_3.1">3.1&nbsp;&nbsp;过程</a></h2>
<p> 我们已经看到了许多的基本过程，例如，<code class=scheme><span class=variable>cons</span></code>, <code class=scheme><span class=variable>string-&gt;list</span></code> 及其他。用户可以通过特殊形式  <code class=scheme><span class=keyword>lambda</span></code> 来创建他们自己的过程。例如，下面定义了一个将它的参数加 <code class=scheme><span class=selfeval>2</span></code> 的过程：</p>
<p>
</p>
<pre class=scheme>(<span class=keyword>lambda</span> (<span class=variable>x</span>) (<span class=variable>+</span> <span class=variable>x</span> <span class=selfeval>2</span>))
</pre><p></p>
<p> 第一个子式 <code class=scheme>(<span class=variable>x</span>)</code> 是参数表。余下的组成了过程的过程体。可以用一个参数来调用那个这个过程，就像调用一个基本过程： </p>
<p>
</p>
<pre class=scheme>((<span class=keyword>lambda</span> (<span class=variable>x</span>) (<span class=variable>+</span> <span class=variable>x</span> <span class=selfeval>2</span>)) <span class=selfeval>5</span>)
<span style="color: teal"><tt><strong>=&gt;</strong></tt></span>  <span class=selfeval>7</span>
</pre><p></p>
<p>如果我们想要多次调用这个过程，我们可以每次拷贝这个 <code class=scheme><span class=keyword>lambda</span></code> ，但我们可以做的更好，通过使用一个变量来保存这个过程： </p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>add2</span>
  (<span class=keyword>lambda</span> (<span class=variable>x</span>) (<span class=variable>+</span> <span class=variable>x</span> <span class=selfeval>2</span>)))
</pre><p></p>
<p> 这样，我们就可以在每次需要为参数加 <code class=scheme><span class=selfeval>2</span></code>   时使用变量   <code class=scheme><span class=variable>add2</span></code> ： </p>
<p>
</p>
<pre class=scheme>(<span class=variable>add2</span> <span class=selfeval>4</span>) <span style="color: teal"><tt><strong>=&gt;</strong></tt></span>  <span class=selfeval>6</span>
(<span class=variable>add2</span> <span class=selfeval>9</span>) <span style="color: teal"><tt><strong>=&gt;</strong></tt></span>  <span class=selfeval>11</span>
</pre><p></p>
<p>
<a name="node_idx_242"></a></p>
<a name="node_sec_3.1.1"></a>
<h3 class=section><a href="t-y-scheme-Z-H-1.html#node_toc_node_sec_3.1.1">3.1.1&nbsp;&nbsp;过程参数</a></h3>
<p><code class=scheme><span class=keyword>lambda</span></code> 过程的参数是由它的第一个子式确定的（就是那个直接跟在符号 <code class=scheme><span class=keyword>lambda</span></code>   后面的形式）。<code class=scheme><span class=variable>add2</span></code> 是一个只有一个参数的过程或叫<em>一元</em>过程，因此它的参数列表是一个只有一个元素的表 <code class=scheme>(<span class=variable>x</span>)</code>。符号   <code class=scheme><span class=variable>x</span></code> 保存了这个过程的参数。<code class=scheme><span class=variable>x</span></code> 的每次出现都是指向过程的参数的。变量 <code class=scheme><span class=variable>x</span></code> 对过程体而言是<em>局部</em>（<em>local</em>）变量。</p>
<p>我们可以为需要 2 个参数的过程提供只有 2 个元素的表，而且一般的，为需要 n 个参数的过程提供有一个有 n 个元素的表。下面的是一个需要 2 个参数来计算矩形的面积的过程。这 2 个参数为矩形的长度和宽度。 </p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>area</span>
  (<span class=keyword>lambda</span> (<span class=variable>length</span> <span class=variable>breadth</span>)
    (<span class=variable>*</span> <span class=variable>length</span> <span class=variable>breadth</span>)))
</pre><p></p>
<p> 注意到 <code class=scheme><span class=variable>area</span></code> 使它的参数相乘，基本过程 <code class=scheme><span class=variable>*</span></code> 也是如此。我们可以这样简单的表示： </p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>area</span> <span class=variable>*</span>)
</pre><p></p>
<p>
</p>
<a name="node_sec_3.1.2"></a>
<h3 class=section><a href="t-y-scheme-Z-H-1.html#node_toc_node_sec_3.1.2">3.1.2&nbsp;&nbsp;不定参数</a></h3>
<p> 一些过程可以不同调用中使用不同数目的参数。为了做到这个， <code class=scheme><span class=keyword>lambda</span></code>   的参数列表被一个单一的符号代替。这个符号作为一个变量被约束到调用这个过程的参数列表上。</p>
<p> 一般而言， <code class=scheme><span class=keyword>lambda</span></code> 的参数列表可以为形式 <code class=scheme>(<span class=variable>x</span> ...)</code> 的表 ，一个符号，或是形式 <code class=scheme>(<span class=variable>x</span> ... . <span class=variable>z</span>)</code> 的点对。在点对这种情况下，所有在点前面的参数都会被约束到被调用过程的对应参数上，而点后的那个单一的变量则会指向一个所有剩下参数组成的表。</p>
<p>
<a name="node_idx_244"></a></p>
<p>
</p>
<a name="node_sec_3.2"></a>
<h2 class=section><a href="t-y-scheme-Z-H-1.html#node_toc_node_sec_3.2">3.2&nbsp;&nbsp;<code class=scheme><span class=variable>apply</span></code></a></h2>
<p>Scheme   过程   <code class=scheme><span class=variable>apply</span></code> 使我们可以对一个作为参数的<em>表</em>调用某个过程。</p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>x</span> <span class=keyword>'</span>(<span class=selfeval>1</span> <span class=selfeval>2</span> <span class=selfeval>3</span>))

(<span class=variable>apply</span> <span class=variable>+</span> <span class=variable>x</span>)
<span style="color: teal"><tt><strong>=&gt;</strong></tt></span>  <span class=selfeval>6</span>
</pre><p></p>
<p> 一般而言， <code class=scheme><span class=variable>apply</span></code> 接收一个过程，后面跟着数目不定的参数，而且最后一个参数必须是一个表。它用所有中间的参数和最后的那个表构造一个参数表。然后返回在这个参数表上调用这个过程得到的结果。例如，    </p>
<p>
</p>
<pre class=scheme>(<span class=variable>apply</span> <span class=variable>+</span> <span class=selfeval>1</span> <span class=selfeval>2</span> <span class=selfeval>3</span> <span class=variable>x</span>)
<span style="color: teal"><tt><strong>=&gt;</strong></tt></span>  <span class=selfeval>12</span>
</pre><p></p>
<p>
<a name="node_idx_246"></a></p>
<p>
</p>
<a name="node_sec_3.3"></a>
<h2 class=section><a href="t-y-scheme-Z-H-1.html#node_toc_node_sec_3.3">3.3&nbsp;&nbsp;顺序</a></h2>
<p> 我们使用特殊形式 <code class=scheme><span class=keyword>begin</span></code> 来捆绑一组需要按顺序求值的子式。许多的 Scheme 形式都有<em>隐式</em>（<em>emplicit</em>）的 <code class=scheme><span class=keyword>begin</span></code>。例如，让我们定义一个有 3 个参数的过程来显示它的 3 个参数，并用空格隔开。一个可能的定义为：  </p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>display3</span>
  (<span class=keyword>lambda</span> (<span class=variable>arg1</span> <span class=variable>arg2</span> <span class=variable>arg3</span>)
    (<span class=keyword>begin</span>
      (<span class=variable>display</span> <span class=variable>arg1</span>)
      (<span class=variable>display</span> <span class=selfeval>&quot; &quot;</span>)
      (<span class=variable>display</span> <span class=variable>arg2</span>)
      (<span class=variable>display</span> <span class=selfeval>&quot; &quot;</span>)
      (<span class=variable>display</span> <span class=variable>arg3</span>)
      (<span class=variable>newline</span>))))
</pre><p></p>
<p>
<a name="node_idx_248"></a></p>
<p> 在 Scheme 中，<code class=scheme><span class=keyword>lambda</span></code> 过程体是隐式的 <code class=scheme><span class=keyword>begin</span></code> 。因此，   <code class=scheme><span class=keyword>begin</span></code> 在 <code class=scheme><span class=variable>display3</span></code> 的过程体中是不需要的，虽然这并不会产生不利。 <code class=scheme><span class=variable>display3</span></code> 更简单的版本是： </p>
<p>
</p>
<pre class=scheme>(<span class=keyword>define</span> <span class=variable>display3</span>
  (<span class=keyword>lambda</span> (<span class=variable>arg1</span> <span class=variable>arg2</span> <span class=variable>arg3</span>)
    (<span class=variable>display</span> <span class=variable>arg1</span>)
    (<span class=variable>display</span> <span class=selfeval>&quot; &quot;</span>)
    (<span class=variable>display</span> <span class=variable>arg2</span>)
    (<span class=variable>display</span> <span class=selfeval>&quot; &quot;</span>)
    (<span class=variable>display</span> <span class=variable>arg3</span>)
    (<span class=variable>newline</span>)))
</pre><p>
</p>
<p>
</p>
<div class=smallskip></div>
<p style="margin-top: 0pt; margin-bottom: 0pt">
<div align=right class=navigation>[Go to <span><a href="t-y-scheme.html">first</a>, <a href="t-y-scheme-Z-H-4.html">previous</a></span><span>, <a href="t-y-scheme-Z-H-6.html">next</a></span> page<span>; &nbsp;&nbsp;</span><span><a href="t-y-scheme-Z-H-1.html#node_toc_start">contents</a></span><span><span>; &nbsp;&nbsp;</span><a href="t-y-scheme-Z-H-25.html#node_index_start">index</a></span>]</div>
</p>
<p></p>
</div>
</body>
</html>
